package com.lcifn.middleware.rpc.server.handler;

import com.lcifn.middleware.rpc.client.stub.RpcRequest;
import com.lcifn.middleware.rpc.client.stub.ServiceType;
import com.lcifn.middleware.rpc.serializer.SerializerSupport;
import com.lcifn.middleware.rpc.server.ServiceProviderRegistry;
import com.lcifn.middleware.rpc.spi.ServiceSupport;
import com.lcifn.middleware.rpc.transport.command.Code;
import com.lcifn.middleware.rpc.transport.command.Command;
import com.lcifn.middleware.rpc.transport.command.Header;
import com.lcifn.middleware.rpc.transport.command.ResponseHeader;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

/**
 * rpc请求Handler
 * @author lichao
 * @date 2021/2/1 18:08
 */
public class RpcRequestHandler implements RequestHandler {

    private static final Logger logger = LoggerFactory.getLogger(RpcRequestHandler.class);

    private final ServiceProviderRegistry serviceRegistry = ServiceProviderRegistry.getInstance();

    /**
     * 处理RPC请求
     *
     * @param reqCommand
     * @return
     */
    @Override
    public Command handle(Command reqCommand) {
        Header header = reqCommand.getHeader();
        // 1. 反序列化获取rpc请求实体
        RpcRequest rpcRequest = SerializerSupport.deserialize(reqCommand.getPayload(), RpcRequest.class);

        String interfaceName = rpcRequest.getInterfaceName();
        String methodName = rpcRequest.getMethodName();
        try {
            // 2. 获取服务对象
            Object service = serviceRegistry.getService(interfaceName);
            if (service != null) {
                // 3. 获取方法参数
                Class[] parameterTypes = SerializerSupport.deserialize(rpcRequest.getParameterTypes(), Class[].class);
                Object[] parameterValues = SerializerSupport.deserialize(rpcRequest.getParameterValues(), Object[].class);

                // 4. 反射调用服务对象的请求方法
                Method method = service.getClass().getMethod(methodName, parameterTypes);
                Object returnVal = method.invoke(service, parameterValues);
                // 5. 组装响应Command
                return new Command(new ResponseHeader(header), SerializerSupport.serialize(returnVal));
            } else {
                logger.error("Not found provider for {}#{}.", interfaceName, methodName);
                return errorCommand(header, Code.NO_PROVIDER);
            }
        } catch (NoSuchMethodException e) {
            logger.error("Not found method {} in class {}.", methodName, interfaceName);
            return errorCommand(header, Code.NOT_FOUND_METHOD);
        } catch (IllegalAccessException | InvocationTargetException e) {
            logger.error("Error invoke method {} in class {}.", methodName, interfaceName, e);
            return errorCommand(header, Code.NOT_FOUND_METHOD);
        }
    }

    /**
     * 返回错误响应
     * @param header
     * @param errorCode
     * @return
     */
    private Command errorCommand(Header header, Code errorCode) {
        return new Command(new ResponseHeader(header, errorCode.getCode(), errorCode.getMessage()), new byte[0]);
    }

    /**
     * handler类型
     *
     * @return
     */
    @Override
    public int type() {
        return ServiceType.RPC_REQUEST;
    }
}
